package com.aaa.config;


import com.aaa.entity.Leadingusers;
import com.aaa.service.UsersDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.Map;

/**
 * oauth2.0配置信息
 */
@EnableAuthorizationServer
@Configuration
public class OauthConfig extends AuthorizationServerConfigurerAdapter {

    //注入认证管理器
    @Autowired
    private AuthenticationManager authenticationManager;

    //注入获取用户身份的实现类对象
    @Autowired
    private UsersDetailServiceImpl usersDetailServiceImpl;

    /**
     * 密码匹配器
     *
     * @return
     */
    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     * 配置jwt生成和解析的需要的秘钥
     *
     * @return
     */
    @Bean
    protected JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter() {
            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                OAuth2AccessToken enhance = super.enhance(accessToken, authentication);
                //把我们需要自定义的东西加到 OAuth2AccessToken中
                Map<String, Object> additionalInformation = enhance.getAdditionalInformation();
                Leadingusers user = (Leadingusers) authentication.getUserAuthentication().getPrincipal();
                //user的密码不要往前端传，
                user.setPassword(null);
                additionalInformation.put("user", user);
                return enhance;
            }
        };

        jwtAccessTokenConverter.setSigningKey("dev");
        return jwtAccessTokenConverter;
    }

    /**
     * 在spring容器中放置JwtTokenStore 注意 生成jwt需要秘钥所有需要注入JwtAccessTokenConverter
     *
     * @return
     */
    @Bean
    protected TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }


    //配置认证凭证信息 这里配置jwtAccessTokenConverter是因为解析jwt需要秘钥
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter()).authenticationManager(authenticationManager).userDetailsService(usersDetailServiceImpl);

    }
    ////////jwt 新加的内容结束///////////////////////////////////////////
    ////////jwt 新加的内容结束///////////////////////////////////////////
    ////////jwt 新加的内容结束///////////////////////////////////////////


    /**
     * 配置第三方客户端信息 刚开会学这玩意，先简单点 ，把第三方客户端信息放到内存中
     *
     * @param clients
     * @throws Exception
     */
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //把
        clients.inMemory()
                //客户端id
                .withClient("user-client")
                //客户端密码
                .secret(new BCryptPasswordEncoder().encode("user-secret-8888"))
                /**
                 * 支持哪些认证模式
                 * authorization_code 授权码模式
                 * password 密码模式
                 * implicit 简单模式
                 * client_credentials 客户端模式
                 * refresh_token 这个不是一种模式 是支持刷新令牌的意思
                 */
                .authorizedGrantTypes("authorization_code", "password", "implicit", "client_credentials", "refresh_token")
                //token有效期 5分钟
                .accessTokenValiditySeconds(50 * 60)
                //刷新token有效期 24小时
                .refreshTokenValiditySeconds(24 * 3600)
                //权限范围
                .scopes("all")
                //授权码模式手动校验 不自动校验
                .autoApprove(false).
                //第三方客户端回调地址 用来返回验证码
                        redirectUris("http://www.baidu.com");
    }

    /**
     * 配置安全策略
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //security.支持远程token访问.支持远程token校验.让密码模式获取令牌的时候/oauth/token支持client_id以及client_secret作为form参数做登录认证
        security.tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
    }
}


